/****************************************************************************************/
/*                                                                     					*/
/*  M16C/62P Group Program Collection                                  					*/
/*                                                                     					*/
/*  FILE NAME : command.c                                  		     					*/
/*  CPU       : This program is the Serial flash boot loader by Xmodem data transfer	*/
/*  HISTORY   : 2006.12.08 Ver 0.01                                    					*/
/*                                                                    	 				*/
/*  Copyright (C) 2006. Renesas Technology Corp.                       					*/
/*  Copyright (C) 2006. Renesas Solutions Corp.                        					*/
/*  All right reserved.                                                					*/
/*                                                                     					*/
/*****************************************************************************************/

/**************************************/
/*    include file                    */
/**************************************/
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include "command.h"
#include "serial.h"
#include "delay_timer.h"
#include "mot.h"
#include "flash_header.h"

/****************************************/
/*    InitCommandHandler function       */
/****************************************/
void InitCommandHandler (void)
{
	InitSci();
	InitDelayTimer();
	
	// copy all RAM based code to RAM
	memcpy( (void *) INT_RAM_BASE_ADDRESS, (void *) RAM_BASED_ROM_ADDRESS, SIZE_OF_RAM_BASED_ROM );

	memcpy( (void *) 0x6000, (void *) 0xFE000, 0x100 ); //fify 20100119 copy VECTOR to RAM
	_asm("	ldc	#0,INTBH");
	_asm("	ldc	#06000h,INTBL");
	
	CommInit();
}

#pragma SECTION program ram_based_prg

//
// functionality of this handler will be dependent on the communication hardware interface
//
/**************************************/
/*    RunCommandHandler function      */
/**************************************/
void RunCommandHandler (void)
{
	unsigned long far *ptr;
	
	pt2FunctionErase fp;		// function pointer used to call target program
	union union_c2s c2s;
	
	// check if bootloader should run by detecting activity for a 3 seconds on the
	// UART channel
	c2s.us = GetByte (3000);
	
	if ( c2s.uc[0] == TIMEOUT )
	{
		// timed out - call target app if reset vector is valid
		ptr = (unsigned long far *)( FIRST_USER_FLASH_ADDR + RESET_VECTOR_OFFSET );
		if ( *ptr != 0xffffffff )
		{
			// call user program and never return
			fp = (pt2FunctionErase) *ptr;
			fp( 0, 0);
		}
		else
		{
			// return back to main
			return;
		}
	}
	else
	{
		// serial activity detected
		// clear buffer
		// loop until we get a timeout
		PurgeComms( 250 );	
		// display menu
 		ShowMenu();
			
		while (1)
		{
			// timeout is not important as we know we have a byte waiting for us
			c2s.us = GetByte (100000);
			if ( c2s.uc[0] == OK )
			{
				switch ( c2s.uc[1] )
				{
					case '1':
					    command(1);
						ShowMenu();	
					break;
					
					case '2':
					    command(2);
						ShowMenu();	
					break;
					
					case '3':
					    command(3);
						ShowMenu();	
					break;

					case '4':
						run_command();		// run target application
					break;
					
				    default:
					    ShowMenu();
					break;
				}
			}
		}
	}
}

//make sure the const string message is in the RAM area //fify20100119
#pragma SECTION rom string_in_ram

/**************************************/
/*    ShowMenu function               */
/**************************************/
void ShowMenu (void)
{
	SendString( "\r\nM16C/62P(384KB) Bootloader -- " );
	SendString(__DATE__);
	SendString( "\r\n------------------------------------------------------\r\n"  );
	SendString( "\r\n1 - Download Application To [A0000-FDFFF][0F000-0FFFF]\r\n" );
	SendString( "\r\n2 - Download Bootloader  To [FE000-FFFFF]\r\n" );
	SendString( "\r\n3 - Download Boot + App  To [A0000-FFFFF][0F000-0FFFF]\r\n" );
	SendString( "\r\n4 - Start User Program\r\n\r\n" );
	SendByte( '>' );
}

/**************************************/
/*    Command_4 function              */
/**************************************/
void command(unsigned char cmd)
{
	unsigned char uc;
    // download data using xmodem and program into flash
    unsigned char Status, Shift;
	volatile unsigned long Address, ul;
	union union_c2s c2s;
	
	unsigned char first_block, last_block;
	
	switch(cmd)
	{
		case 1:
			SendString( "\r\nErase area [0F000-0FFFF][A0000-FDFFF] (Y/N)?" );
			first_block = 2;
			last_block = 11;
		break;
		case 2:
		    SendString( "\r\nErase area [FE000-FFFFF] (Y/N)?" );
			first_block = 0;
			last_block = 1;
		break;
		case 3:
		    SendString( "\r\nErase area [0F000-0FFFF][A0000-FFFFF] (Y/N)?" );
			first_block = 0;
			last_block = 11;
		break;
	}
	
	c2s.us = GetByte( 10000 );
	SendByte( c2s.uc[1] );
	if ( c2s.uc[0] == TIMEOUT )
	{
		SendString( "\r\nTimed out waiting for response" );
		return;
	}
	else if ( c2s.uc[0] == ERROR )
	{
		SendString( "\r\nComms error" );
		return;
	}
	else if ( !( ( c2s.uc[1] == 'y' ) || ( c2s.uc[1] == 'Y' ) ) )
	{
		SendString( "\r\nAll blocks erase cancelled" );
		return;
	}

	for( uc=first_block; uc<last_block+1; uc++ )
	{
		SendString( "\r\nErasing block " );
		if( uc < 10 )
		{
			SendByte( uc + 48 );
		}
		else
		{
			SendByte( ( uc / 10 ) + 48 );
			SendByte( ( uc % 10 ) + 48 );
		}
		
		SendString ( "..." );
		// call the erase function with the block to be erased and a dummy value (0)
		Status = BlockErase ( uc, 0 );

		if ( Status == ERASE_FAIL )
		{
			SendString( "Erasing of block " );
			SendByte( uc + 48 );
			SendString( " FAILED\r\n" );
			return;
		}
		else
		{
			SendString( "OK" );
		}
	}

	SendString( "\r\nAll user blocks erased" );
		
	SendString( "\r\nDownload MOT and Program Flash (Y/N)?" );
	c2s.us = GetByte( 10000 );
	SendByte( c2s.uc[1] );
	if ( c2s.uc[0] == TIMEOUT )
	{
		SendString( "\r\nTimed out waiting for response" );
		return;
	}
	else if ( c2s.uc[0] == ERROR )
	{
		SendString( "\r\nComms error" );
		return;
	}
	else if ( !( ( c2s.uc[1] == 'y' ) || ( c2s.uc[1] == 'Y' ) ) )
	{
		SendString( "\r\nFlash programming cancelled" );
		return;
	}
	
	SendString( "\r\nTransfer -> Send ASCII... to select MOT file ...\r\n" );
	
	// start xmodem download and program the flash with the downloaded data
	Status = MotDownloadAndProgramFlash();
		
	if ( Status == MOT_TIMEOUT )
		SendString( "Timeout" );
	else if ( Status == MOT_OK )
		SendString( "\r\nOK, press 4 to Start User Program now" );
	else if ( Status == MOT_PROG_FAIL )
		SendString( "Flash program FAIL" );
	else if ( Status == MOT_COMMS_ERROR)
	    SendString( "MOT_COMMS_ERROR" );

	SendString("\r\n");
	
	PurgeComms( 1000 );
}

/**************************************/
/*    Command_5 function              */
/**************************************/
void run_command(void)
{
	// call the target application
	union union_c2s c2s;
	unsigned long far *ptr;
	pt2FunctionErase fp;
	
	SendString( "\r\nRun user program (Y/N)?" );
	c2s.us = GetByte( 10000 );
	SendByte( c2s.uc[1] );
	if ( c2s.uc[0] == TIMEOUT )
	{
		SendString( "\r\nTimed out waiting for response" );
		return;
	}
	else if ( c2s.uc[0] == ERROR )
	{
		SendString( "\r\nComms error" );
		return;
	}
	else if ( !( ( c2s.uc[1] == 'y' ) || ( c2s.uc[1] == 'Y' ) ) )
	{
		SendString( "\r\nRun user program request cancelled" );
		return;
	}
	
	SendString("\r\n");
	
	// run user program
	// check user reset address is not all erased
	ptr = (unsigned long far *) ( FIRST_USER_FLASH_ADDR + RESET_VECTOR_OFFSET );
	if ( *ptr != 0xffffffff )
	{
		SendString( "Running user program..." );
		// call user program and never return
		fp = (pt2FunctionErase) *ptr;
		fp( 0, 0);
	}
	else
	{
		// invalid user reset address
		SendString( "Invalid user reset address.  Staying put." );
		return;
	}
}
